#include "MultiModel.h"

#ifndef TINYOBJLOADER_IMPLEMENTATION
#define TINYOBJLOADER_IMPLEMENTATION
#endif

#include "utils/tiny_obj_loader.h"
#include "../../Utils/FileUtil.h"
#include <unordered_map>

MultiModel::MultiModel(const std::string objPath, const std::string mtlDir)
{
	tinyobj::attrib_t attrib;
	std::vector<tinyobj::shape_t> shapes;
	std::vector<tinyobj::material_t> materials;
	std::string warn, err;
	std::string objFilePath = FileUtil::GetAssetPath() + std::string("\\Models\\") + objPath;
	std::string mtlFileDir = FileUtil::GetAssetPath() + std::string("\\Models\\") + mtlDir;
	assert(tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err, objFilePath.c_str(), mtlFileDir.c_str()));


	mVertexGroups.resize(materials.size() + 1);
	mIndiceGroups.resize(materials.size() + 1);
	std::vector<std::unordered_map <Vertex, uint32>> uniqueVerticesPerGroup(materials.size() + 1);

	auto appendVertex = [&uniqueVerticesPerGroup, this](const Vertex& vertex, int32 materialId)
	{
		auto& uniqueVertices = uniqueVerticesPerGroup[materialId + 1];
		auto& vertexs = mVertexGroups[materialId + 1];
		auto& indices = mIndiceGroups[materialId + 1];

		if (uniqueVertices.count(vertex) == 0)
		{
			uniqueVertices[vertex] = vertexs.size();
			vertexs.push_back(vertex);
		}
		indices.push_back(uniqueVertices[vertex]);
	};



	for (int32 i = 0; i < shapes.size(); ++i)
	{
		std::vector<Vertex> vertexs;
		std::vector<uint32> indices;

		int32 indexOffset = 0;
		for (int32 j = 0; j < shapes[i].mesh.num_face_vertices.size(); ++j)
		{
			uint8 ngon = shapes[i].mesh.num_face_vertices[j];
			int32 materialId = shapes[i].mesh.material_ids[j];

			for (uint8 k = 0; k < ngon; ++k)
			{
				const auto& index = shapes[i].mesh.indices[indexOffset + k];

				Vertex vertex{};

				vertex.Position = {
					attrib.vertices[3 * index.vertex_index + 0],
					attrib.vertices[3 * index.vertex_index + 1],
					attrib.vertices[3 * index.vertex_index + 2]
				};

				vertex.TexC = {
					attrib.texcoords[2 * index.texcoord_index + 0],
					1.0f - attrib.texcoords[2 * index.texcoord_index + 1]
				};

				vertex.Normal = {
					attrib.normals[3 * index.normal_index + 0],
					attrib.normals[3 * index.normal_index + 1],
					attrib.normals[3 * index.normal_index + 2]
				};

				appendVertex(vertex, materialId);
			}
			indexOffset += ngon;
		}
	}

	if (mVertexGroups.size() > 1)
	{
		mVertexGroups.erase(mVertexGroups.begin());
		mIndiceGroups.erase(mIndiceGroups.begin());
	}
}


